package user

import (
	"administrator/app/apputils/tokenutils"
	"administrator/app/log"
	"administrator/app/mapper"
	"administrator/app/model"
	"context"
	"database/sql"
	"encoding/json"
	"errors"
	"fmt"
	"gitee.com/aurora-engine/utils/datautils"
	"gitee.com/aurora-engine/utils/rep"
	"gitee.com/aurora-engine/utils/treeutils"
	"gitee.com/aurora-engine/web"
	amqp "github.com/rabbitmq/amqp091-go"
	"github.com/tencentyun/cos-go-sdk-v5"
	"mime/multipart"
	"net/http"
	"nhooyr.io/websocket"
	"strings"
	"time"
)

/*
	用户管理
*/

type Control struct {
	*mapper.UserMapper
	*mapper.OrgManageMapper
	*sql.DB
	Ak         string        `value:"aurora.baiduAk"`
	HeadAddUrl string        `value:"aurora.oss.BucketURL"`
	Channel    *amqp.Channel // rabbitMQ 通道
	Tenc       *cos.Client
}

func New() web.Constructor {
	return func() any {
		return &Control{}
	}
}

type Login struct {
	Account  string
	Password string
}

// Login 登录接口
func (control *Control) Login(login Login) (rep.Response, error) {
	var orgs []int
	var orgInfo []map[string]any
	var allOrg []*model.Org
	var user *model.UserModel
	var roles []*model.UrInfo
	var err error
	if user, err = control.SelectUser(login); user == nil || err != nil {
		log.Error(err.Error())
		return rep.Fail(err, "登录失败"), err
	}
	if *user == (model.UserModel{}) {
		err = errors.New("密码错误")
		return rep.Fail(err, "登录失败"), err
	}
	token := tokenutils.CreateToken(*user)
	user.Password = ""
	params := map[string]int{"uid": user.Id}
	// 查询用户所加入的所有组织
	if orgs, err = control.UserOrg(params); err != nil {
		return rep.Fail(err, "登录失败"), err
	}

	// 查询所有组织
	if allOrg, err = control.AllOrg(nil); err != nil {
		return rep.Fail(err, "登录失败"), err
	}
	tree := treeutils.Tree(1, allOrg)
	// 解析组织
	for _, org := range orgs {
		name := treeutils.FullName(org, tree)
		fullName := strings.Join(name, "-")
		orgInfo = append(orgInfo, map[string]any{"orgId": org, "name": fullName})
	}

	// 查询角色所在组织的所有角色信息
	if roles, err = control.UserRoles(params); err != nil {
		return rep.Fail(err, "登录失败"), err
	}
	data := map[string]any{
		"token": token,
		"user":  user,
		"orgs":  orgInfo,
		"roles": roles,
	}
	return rep.Success(data, "登录成功"), nil
}

// Info
// @Description :
// @Param token :
// [Get] => /api/user/info
func (control *Control) Info(token *tokenutils.Token) (rep.Response, error) {
	var orgs []int
	var orgInfo []map[string]any
	var allOrg []*model.Org
	var roles []*model.UrInfo
	var user *model.UserModel
	var err error
	params := map[string]int{"uid": token.ID}
	if user, err = control.UserInfo(params); err != nil {
		return rep.Fail(err, "基础信息获取失败"), err
	}
	user.Password = ""
	// 查询用户所加入的所有组织
	if orgs, err = control.UserOrg(params); err != nil {
		return rep.Fail(err, "组织信息获取失败"), err
	}
	// 查询所有组织
	if allOrg, err = control.AllOrg(nil); err != nil {
		return rep.Fail(err, "组织信息获取失败"), err
	}
	tree := treeutils.Tree(1, allOrg)
	// 解析组织
	for _, org := range orgs {
		name := treeutils.FullName(org, tree)
		fullName := strings.Join(name, "-")
		orgInfo = append(orgInfo, map[string]any{"orgId": org, "name": fullName})
	}

	// 查询角色所在组织的所有角色信息
	if roles, err = control.UserRoles(params); err != nil {
		return rep.Fail(err, "组织信息获取失败"), err
	}
	data := map[string]any{
		"user":  user,
		"orgs":  orgInfo,
		"roles": roles,
	}
	return rep.Success(data, "获取成功"), nil
}

// EditInfo
// @Description :
// @Param args :
// @Param token :
// [Post] => /api/user/setting/info
func (control *Control) EditInfo(args *model.UserModel, token *tokenutils.Token) (rep.Response, error) {
	var err error
	args.Id = token.ID
	if err = control.UpdateBaseInfo(args); err != nil {
		return rep.Fail(err, "更新失败"), err
	}
	return rep.Success(true, "修改成功"), nil
}

// DefaultOrgRole
// @Description :
// @Param arg :
// @Param token :
// [Get] => /api/default/our
func (control *Control) DefaultOrgRole(token *tokenutils.Token, arg map[string]int) (rep.Response, error) {
	var role int
	var err error
	if _, ok := arg["org"]; !ok {
		err = errors.New("请求参数错误")
		return rep.Fail(err, "org 参数不存在"), err
	}
	arg["id"] = token.ID
	if role, err = control.GetOrgDefaultRole(arg); err != nil {
		return rep.Fail(err, "组织角色查询失败"), err
	}
	return rep.Success(role), nil
}

// SetDefaultOrg
// @Description : 设置用户的默认组织
// @Param args :
// @Param token :
// [Post] => /api/org/default
func (control *Control) SetDefaultOrg(token *tokenutils.Token, args map[string]int) (rep.Response, error) {
	var err error
	var role int
	args["id"] = token.ID
	if args["org"] == 0 {
		return rep.Response{}, err
	}
	// 查询组织的默认角色
	if role, err = control.GetOrgDefaultRole(args); err != nil {
		return rep.Response{}, err
	}
	args["role"] = role
	// 更新用户当前默认组织及其角色
	if err = control.UpdateUserOR(args); err != nil {
		return rep.Fail(err, "更新失败"), err
	}
	return rep.Success(true), nil
}

// SetDefaultOrgRole
// @Description : 设置组织默认角色,只有当前默认组织才能够修改默认角色
// @Param args :
// @Param token :
// [Post] => /api/user/role/default
func (control *Control) SetDefaultOrgRole(token *tokenutils.Token, args map[string]int) (rep.Response, error) {
	var err error
	args["uid"] = token.ID
	if args["role"] == 0 || args["org"] == 0 {
		return rep.Fail(nil, "参数错误"), errors.New("参数错误")
	}
	begin, err := control.DB.Begin()
	if err != nil {
		return rep.Response{}, err
	}

	// 查询当前用户的 角色信息
	var info *model.UserModel
	if info, err = control.GetUserDefaultOrgInfo(args); err != nil {
		return rep.Fail(err, "参数错误"), errors.New("参数错误")
	}

	orgId, err := datautils.Get[int](info.OrgId)
	if err != nil {
		return rep.Response{}, err
	}

	// 修改的组织为用户默认组织的角色 需要一起更新用户表
	if args["org"] == orgId {
		if err = control.UpdateUserRole(args, begin); err != nil {
			begin.Rollback()
			return rep.Fail(err, "修改失败"), err
		}
	}
	if err = control.UpdateOrgRole(args, begin); err != nil {
		begin.Rollback()
		return rep.Fail(err, "修改失败"), err
	}
	begin.Commit()

	// 返回最新的用户信息到前端
	var orgs []int
	var allOrg []*model.Org
	var roles []*model.UrInfo
	var orgInfo []map[string]any
	params := map[string]int{"uid": token.ID}
	// 查询用户所加入的所有组织
	if orgs, err = control.UserOrg(params); err != nil {
		return rep.Fail(err, "组织查询失败"), err
	}

	// 查询所有组织
	if allOrg, err = control.AllOrg(nil); err != nil {
		return rep.Fail(err, "组织查询失败"), err
	}
	tree := treeutils.Tree(1, allOrg)
	// 解析组织
	for _, org := range orgs {
		name := treeutils.FullName(org, tree)
		fullName := strings.Join(name, "-")
		orgInfo = append(orgInfo, map[string]any{"orgId": org, "name": fullName})
	}

	// 查询角色所在组织的所有角色信息
	if roles, err = control.UserRoles(params); err != nil {
		return rep.Fail(err, "组织角色信息查询失败"), err
	}
	data := map[string]any{
		"orgs":  orgInfo,
		"roles": roles,
	}
	return rep.Success(data), nil
}

// Message
// @Description : 登录 系统创建消息长连接
// @Param rew :
// @Param req :
// [Get] => /public/ws
func (control *Control) Message(req *http.Request, rew http.ResponseWriter) {
	client, err := websocket.Accept(rew, req, &websocket.AcceptOptions{OriginPatterns: []string{req.Host, "127.0.0.1:5173", "localhost:5173"}})
	if err != nil {
		err := client.Close(websocket.StatusInternalError, "")
		if err != nil {
			return
		}
		return
	}
	ctx, clear := context.WithCancel(context.Background())

	// 开启协程 通过循环倒计时的方式向前端发起 ping 请求
	go func() {
		ticker := time.NewTicker(2 * time.Second)
		for {
			select {
			case <-ticker.C:
				//fmt.Println("ping...")
				err := client.Ping(ctx)
				if err != nil {
					fmt.Println("ping err:", err.Error())
					clear()
					return
				}
				//fmt.Println("ping end...")
			}
		}
	}()

	// 开启协程持续的读取 前端传递来的消息 收到消息后 标识完成一次 ping/pong 心跳
	go func() {
		ticker := time.NewTicker(2 * time.Second)
		for {
			select {
			case <-ticker.C:
				// 修改读取 不输出
				client.Read(ctx)
			case <-ctx.Done():
				fmt.Println("read...close..")
				return
			}
		}
	}()

	// 在合适的机会向前端发送消息给前端
	go func() {
		for {
			select {
			case m := <-Msg:
				err := client.Write(ctx, websocket.MessageText, []byte(m))
				if err != nil {
					fmt.Println(err.Error())
					return
				}
				// 心跳机制断开，将结束连接释放协程资源
			case <-ctx.Done():
				fmt.Println("close...")
				client.Close(websocket.StatusGoingAway, "")
				return
			}
		}
	}()

}

// SettingHeader
// @Description : 用户上传修改头像
// @Param file : 上传的头像文件
// @Param token : 用户信息
// [Post] => /api/user/setting/header
func (control *Control) SettingHeader(file *web.MultipartFile, token *tokenutils.Token) (rep.Response, error) {
	var ok bool
	var err error
	var open multipart.File
	var headers []*multipart.FileHeader

	if len(file.File) == 0 {
		err = errors.New("头像不存在")
		return rep.Fail(err, "头像不存在"), err
	}
	if headers, ok = file.File["image"]; !ok || len(headers) == 0 {
		return rep.Fail(nil, "头像不存在"), err
	}

	if open, err = headers[0].Open(); err != nil {
		return rep.Fail(err, "修改头像失败"), err
	}

	// 创建存储路径
	name := fmt.Sprintf("%d/head/%s", token.ID, headers[0].Filename)

	// 执行推送到对象存储
	if _, err = control.Tenc.Object.Put(context.Background(), name, open, nil); err != nil {
		return rep.Fail(err, "对象存储失败"), err
	}
	full := fmt.Sprintf("%s/%s", control.HeadAddUrl, name)
	// 更新 用户信息
	if err = control.UpdateUserHead(
		map[string]any{
			"img": full,
			"uid": token.ID}); err != nil {
		return rep.Fail(err, "头像上传失败"), err
	}

	return rep.Success(full, "头像修改成功"), nil
}

// QuitOrg
// @Description : 用户退出自己所在的一个组织
// @Param args : orgId(需要退出的组织id) userId(用户id)
// [Post] => /api/user/quit/org
func (control *Control) QuitOrg(args map[string]int) (rep.Response, error) {
	var err error
	// 校验数据
	if args["orgId"] == 0 || args["userId"] == 0 {
		err = errors.New("请求参数错误")
		return rep.Fail(err, "退出失败"), err
	}

	// 用户所在组织是管理员的禁止用户自己退出
	if ids, err := control.IsAdmin(args); len(ids) != 0 || err != nil {
		if err != nil {
			return rep.Fail(err, "退出失败"), err
		}
		if len(ids) != 0 {
			err = errors.New("管理员无法退出组织")
			return rep.Fail(err, "退出失败"), err
		}
	}
	begin, err := control.DB.Begin()
	if err != nil {
		return rep.Fail(err, "退出失败"), err
	}
	// 删除用户和当前组织的的组织关系
	if err = control.OrgDelUser(args, begin); err != nil {
		begin.Rollback()
		return rep.Fail(err, "退出组织关系失败"), err
	}

	// 删除组织默认关系
	if err = control.OrgDelUserDefaultInfo(args, begin); err != nil {
		begin.Rollback()
		return rep.Fail(err, "组织默认信息删除失败"), err
	}

	// 删除当前组织的角色授权
	if err = control.OrgDelUserRoles(args, begin); err != nil {
		begin.Rollback()
		return rep.Fail(err, "删除组织授权失败"), err
	}

	// todo 删除用户对应在组织角色下的菜单,功能权限授权

	if err = begin.Commit(); err != nil {
		return rep.Fail(err, "退出组织失败"), err
	}

	return rep.Success(true, "退出成功"), nil
}

func (control *Control) Send(message map[string]string) {
	Msg <- message["text"]
}

// 获取用户登录地 天气
func (control *Control) getWeather(ip string) {
	client := http.Client{}
	var address any
	var buf []byte = make([]byte, 0)
	// 获取定位
	addressUrl := fmt.Sprintf("https://api.map.baidu.com/location/ip?ak=%s&ip=%s&coor=bd09ll", control.Ak, "172.24.103.36")
	get, err := client.Get(addressUrl)
	if err != nil {
		return
	}
	if get.StatusCode == 200 {
		_, err = get.Body.Read(buf)
		if err != nil {
			panic(err)
		}
		err = json.Unmarshal(buf, &address)
		if err != nil {
			panic(err)
		}
		fmt.Println(address)
	}
}
